#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <error.h>
#include <malloc.h>
#include <sys/mman.h>


#define XDMA_MEM_BUF_MAX_COUNT 4

#define XDMA_MEM_ALLOC_ALIGN 	0x80
#define XDMA_MEM_ALLOC_MAX_LEN 	0x800000


static void * s_xdmaMemBuf[XDMA_MEM_BUF_MAX_COUNT] = {NULL};
static unsigned int s_xdmaMemBufSize[XDMA_MEM_BUF_MAX_COUNT] = {0};
static unsigned int s_xdmaMemBufWrPtr[XDMA_MEM_BUF_MAX_COUNT] = {0};
int s_xdmaMemBufCount = 0;

void xdmaMemBufInit(		void * usrBuf0, unsigned int usrBuf0Size,
								void * usrBuf1, unsigned int usrBuf1Size,
								void * usrBuf2, unsigned int usrBuf2Size,
								void * usrBuf3, unsigned int usrBuf3Size)
{
	s_xdmaMemBufCount = 0;

	if(usrBuf0 == 0)
	{
		s_xdmaMemBuf[s_xdmaMemBufCount] = 0;
	}
	else
	{
		s_xdmaMemBuf[s_xdmaMemBufCount] = usrBuf0;
		s_xdmaMemBufSize[s_xdmaMemBufCount] = usrBuf0Size;
		s_xdmaMemBufWrPtr[s_xdmaMemBufCount] = 0;
		s_xdmaMemBufCount = s_xdmaMemBufCount + 1;

	}

	if(usrBuf1 == 0)
	{
		s_xdmaMemBuf[s_xdmaMemBufCount] = 0;
	}
	else
	{
		s_xdmaMemBuf[s_xdmaMemBufCount] = usrBuf1;
		s_xdmaMemBufSize[s_xdmaMemBufCount] = usrBuf1Size;
		s_xdmaMemBufWrPtr[s_xdmaMemBufCount] = 0;
		s_xdmaMemBufCount = s_xdmaMemBufCount + 1;

	}

	if(usrBuf2 == 0)
	{
		s_xdmaMemBuf[s_xdmaMemBufCount] = 0;
	}
	else
	{
		s_xdmaMemBuf[s_xdmaMemBufCount] = usrBuf2;
		s_xdmaMemBufSize[s_xdmaMemBufCount] = usrBuf2Size;
		s_xdmaMemBufWrPtr[s_xdmaMemBufCount] = 0;
		s_xdmaMemBufCount = s_xdmaMemBufCount + 1;

	}

	if(usrBuf3 == 0)
	{
		s_xdmaMemBuf[s_xdmaMemBufCount] = 0;
	}
	else
	{
		s_xdmaMemBuf[s_xdmaMemBufCount] = usrBuf3;
		s_xdmaMemBufSize[s_xdmaMemBufCount] = usrBuf3Size;
		s_xdmaMemBufWrPtr[s_xdmaMemBufCount] = 0;
		s_xdmaMemBufCount = s_xdmaMemBufCount + 1;

	}
}

unsigned int xdmaMemAlignLen(unsigned int alignment,unsigned int nBytes)
{
	unsigned int mask = 0;
	unsigned int lenAlign = 0;

	lenAlign = nBytes;
	mask = alignment -1;
	lenAlign += mask;
	lenAlign &= (~mask);

	return lenAlign;
}

void * xdmaMemAllocBuf(unsigned int BufIndex, unsigned int align, unsigned int nBytes)
{
	unsigned int len = 0;
	unsigned int wrPtr = 0;

	if(nBytes == 0)
	{
		return NULL;
	}

	if(BufIndex > s_xdmaMemBufCount - 1)
	{
		return NULL;
	}

	if(align%4 != 0)
	{
		return NULL;
	}

	len = xdmaMemAlignLen(align,nBytes);
	if(len >= XDMA_MEM_ALLOC_MAX_LEN)
	{
		len = XDMA_MEM_ALLOC_MAX_LEN;
	}

	wrPtr = s_xdmaMemBufWrPtr[BufIndex];

	if ((wrPtr + len) > s_xdmaMemBufSize[BufIndex])
	{
		wrPtr = 0;
		s_xdmaMemBufWrPtr[BufIndex] = len;
	}
	else
	{
		s_xdmaMemBufWrPtr[BufIndex] = wrPtr + len;
	}

	return (void *) ( s_xdmaMemBuf[BufIndex] + wrPtr);

}
